/**
 * 
 */
package org.wltea.analyzer.dic;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wltea.analyzer.cfg.Configuration;
import org.wltea.analyzer.help.Utils;

/**
 * IK Analyzer v3.2 词典管理类,单子模式
 * 
 * @author 林良益
 * 
 */
public class Dictionary {

    protected static Logger logger = LoggerFactory.getLogger(Dictionary.class);

    /*
     * 词典单子实例
     */
    private static final Dictionary singleton;

    /*
     * 词典初始化
     */
    static {
        singleton = new Dictionary();
    }

    /*
     * 主词典对象
     */
    private DictSegment _MainDict;
    /*
     * 停止词集合
     */
    private DictSegment _StopWords;

    private Dictionary() {
        // 初始化系统词典
        loadMainDict();
        loadStopWordDict();
    }

    /**
     * 加载主词典及扩展词典
     */
    private void loadMainDict() {
        // 建立一个主词典实例
        _MainDict = loadBaseDict(Configuration.DIC_MAIN, false);
        // 加载扩展词典配置
        List<String> extDictFiles = Configuration.getExtDictionarys();
        loadExtDict(extDictFiles, _MainDict, true);
    }

    private DictSegment loadBaseDict(String name, boolean ignore) {
        // 建立一个姓氏词典实例
        DictSegment dictSegment = new DictSegment((char) 0);
        // 读取姓氏词典文件
        String path = Configuration.getBaseDictionaryPath() + name;
        InputStream is = Utils.loadFile(path);
        if (is == null) {
            if (ignore) {
                logger.warn(path + " Dictionary not found!!!");
                return dictSegment;
            }
            throw new RuntimeException(path + " Dictionary not found!!!");
        }
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(is,
                    "UTF-8"), 512);
            String theWord = null;
            do {
                theWord = br.readLine();
                if (theWord != null && !"".equals(theWord.trim())) {
                    dictSegment.fillSegment(theWord.trim().toCharArray());
                }
            } while (theWord != null);
            logger.info("finish load dict " + path);
        } catch (IOException ioe) {
            System.err.println(path + " Dictionary loading exception.");
            ioe.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                    is = null;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return dictSegment;
    }

    private void loadExtDict(List<String> extDictFiles,
            DictSegment dictSegment, boolean isExt) {
        logger.info("extDictFiles:" + extDictFiles);
        if (extDictFiles != null) {
            for (String extDictName : extDictFiles) {
                // 读取扩展词典文件
                InputStream is = Utils.loadFile(extDictName);
                // 如果找不到扩展的字典，则忽略
                if (is == null) {
                    logger.warn("cannot found ext file : " + extDictName);
                    continue;
                }
                try {
                    BufferedReader br = new BufferedReader(
                            new InputStreamReader(is, "UTF-8"), 512);
                    String theWord = null;
                    do {
                        theWord = br.readLine();
                        if (theWord != null && !"".equals(theWord.trim())) {
                            // 加载扩展词典数据到主内存词典中
                            // System.out.println(theWord);
                            dictSegment.fillSegment(theWord.trim()
                                    .toCharArray(), isExt);
                        }
                    } while (theWord != null);
                    logger.info("finish load dict " + extDictName);
                } catch (IOException ioe) {
                    System.err.println(extDictName
                            + " Extension Dictionary loading exception.");
                    ioe.printStackTrace();

                } finally {
                    try {
                        if (is != null) {
                            is.close();
                            is = null;
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * 加载停止词词典
     */
    private void loadStopWordDict() {
        // 建立一个停止词典实例
        _StopWords = loadBaseDict(Configuration.DIC_STOP, true);
        // 加载扩展停止词典
        List<String> extStopWordDictFiles = Configuration
                .getExtStopWordDictionarys();
        loadExtDict(extStopWordDictFiles, _StopWords, false);
    }

    /**
     * 词典初始化 由于IK Analyzer的词典采用Dictionary类的静态方法进行词典初始化
     * 只有当Dictionary类被实际调用时，才会开始载入词典， 这将延长首次分词操作的时间 该方法提供了一个在应用加载阶段就初始化字典的手段
     * 用来缩短首次分词时的时延
     * 
     * @return Dictionary
     */
    public static Dictionary getInstance() {
        return Dictionary.singleton;
    }

    /**
     * 加载扩展的词条
     * 
     * @param extWords
     *            Collection<String>词条列表
     */
    public static void loadExtendWords(Collection<String> extWords) {
        if (extWords != null) {
            for (String extWord : extWords) {
                if (extWord != null) {
                    // 加载扩展词条到主内存词典中
                    singleton._MainDict.fillSegment(extWord.trim()
                            .toCharArray(), true);
                }
            }
        }
    }

    /**
     * 加载扩展的停止词条
     * 
     * @param extStopWords
     *            Collection<String>词条列表
     */
    public static void loadExtendStopWords(Collection<String> extStopWords) {
        if (extStopWords != null) {
            for (String extStopWord : extStopWords) {
                if (extStopWord != null) {
                    // 加载扩展的停止词条
                    singleton._StopWords.fillSegment(extStopWord.trim()
                            .toCharArray());
                }
            }
        }
    }

    public static boolean isInMainDict(String word) {
        Hit hit = singleton._MainDict.match(word.toCharArray());
        return hit.isMatch();
    }

    public static boolean isInExtMainDict(String word) {
        Hit hit = singleton._MainDict.match(word.toCharArray());
        return hit.isMatch() && hit.isExt();
    }

    public static Hit matchInMainDict(String word) {
        return singleton._MainDict.match(word.toCharArray());
    }

    /**
     * 检索匹配主词典
     * 
     * @param charArray
     * @return Hit 匹配结果描述
     */
    public static Hit matchInMainDict(char[] charArray) {
        return singleton._MainDict.match(charArray);
    }

    /**
     * 检索匹配主词典
     * 
     * @param charArray
     * @param begin
     * @param length
     * @return Hit 匹配结果描述
     */
    public static Hit matchInMainDict(char[] charArray, int begin, int length) {
        return singleton._MainDict.match(charArray, begin, length);
    }

    /**
     * 检索匹配主词典, 从已匹配的Hit中直接取出DictSegment，继续向下匹配
     * 
     * @param charArray
     * @param currentIndex
     * @param matchedHit
     * @return Hit
     */
    public static Hit matchWithHit(char[] charArray, int currentIndex,
            Hit matchedHit) {
        DictSegment ds = matchedHit.getMatchedDictSegment();
        return ds.match(charArray, currentIndex, 1, matchedHit);
    }

    public static Hit matchWithHit(char[] charArray, int startIndex, int len,
            Hit hit) {
        int index = 0;
        while (index < len) {
            DictSegment ds = hit.getMatchedDictSegment();
            hit = ds.match(charArray, startIndex + index, 1, hit);
            index++;
            if (!hit.isPrefix()) {
                break;
            }
        }
        if (index < len) {
            hit.setUnmatch();
        }
        return hit;
    }

    /**
     * 判断是否是停止词
     * 
     * @param charArray
     * @param begin
     * @param length
     * @return boolean
     */
    public static boolean isStopWord(char[] charArray, int begin, int length) {
        return singleton._StopWords.match(charArray, begin, length).isMatch();
    }

    public static boolean isStopWord(String word) {
        return singleton._StopWords.match(word.toCharArray(), 0, word.length())
                .isMatch();
    }

}
